﻿using System;
using System.Collections.Generic;
using XNAFight.Engine;

namespace XNAFight.Players
{
    /// Gestionnaire de charge
    /// Donne les charges actives de chaque coup (LP, MP, HP, LK, MK, HK, BACK, DOWN, FORWARD, UP)
    /// Le temps de charge doit être passé au constructeur
    /// Doit être mis à jour à chaque frame avec les derniers mouvements de base 
    class ChargeManager
    {
        #region CHAMPS

        private bool[] available_charges;   // Disponibilité des charges pour les mouvements (dans l'ordre) : LP, MP, HP, LK, MK, HK, BACK, DOWN, FORWARD, UP
        private int[] loading_frames;       // Nombre de frames pendant lesquelles le joueur a chargé les mouvements (dans l'ordre) : LP, MP, HP, LK, MK, HK, BACK, DOWN, FORWARD, UP

        private readonly int loading_frames_needed; // Nombre de frames necessaires pour que la charge soit active

        #endregion

        #region INITIALISATION

        /// Le temps de charge et les temps de conservation de charges doivent être passés au constructeur
        public ChargeManager(int _loading_frames_needed)
        {
            loading_frames_needed = _loading_frames_needed;

            available_charges = new bool[10];
            for (int i  = 0; i < 10; i++)
            {
                available_charges[i] = false;
            }

            loading_frames = new int[10];
            for (int i = 0; i < 10; i++)
            {
                loading_frames[i] = 0;
            }
        }

        #endregion

        #region PROPRIETES
        
        public bool LPunchChargeAvailable
        {
            get { return available_charges[0]; }
        }
        public bool MPunchChargeAvailable
        {
            get { return available_charges[1]; }
        }
        public bool HPunchChargeAvailable
        {
            get { return available_charges[2]; }
        }
        public bool LKickChargeAvailable
        {
            get { return available_charges[3]; }
        }
        public bool MKickChargeAvailable
        {
            get { return available_charges[4]; }
        }
        public bool HKickChargeAvailable
        {
            get { return available_charges[5]; }
        }
        public bool BackChargeAvailable
        {
            get { return available_charges[6]; }
        }
        public bool DownChargeAvailable
        {
            get { return available_charges[7]; }
        }
        public bool ForwardChargeAvailable
        {
            get { return available_charges[8]; }
        }
        public bool UpChargeAvailable
        {
            get { return available_charges[9]; }
        }
        public bool DownBackChargeAvailable
        {
            get { return (available_charges[6] && available_charges[7]); }
        }
        public bool DownForwardChargeAvailable
        {
            get { return (available_charges[7] && available_charges[8]); }
        }
        public bool UpForwardChargeAvailable
        {
            get { return (available_charges[8] && available_charges[9]); }
        }
        public bool UpBackChargeAvailable
        {
            get { return (available_charges[9] && available_charges[6]); }
        }

        #endregion 

        #region UPDATE

        // Doit être appelée à chaque frame avec les derniers mouvements de base (_last_basic_moves)
        public void Update(List<int> _last_basic_moves)
        {
            #region CHARGE : LP, MP, HP, LK, MK, HK

            int[] moves_id = new int[6];
            moves_id[0] = (int)BMove.LPUNCH;
            moves_id[1] = (int)BMove.MPUNCH;
            moves_id[2] = (int)BMove.HPUNCH;
            moves_id[3] = (int)BMove.LKICK;
            moves_id[4] = (int)BMove.MKICK;
            moves_id[5] = (int)BMove.HKICK;

            // grace au tableau moves_id on passe chacun de ces en coups en revue de la même façon
            for (int i = 0; i < moves_id.Length; i++)
            {
                // Pour savoir si le joueur est en train de charger le coup
                bool loading_move = isMoveHappening(moves_id[i], _last_basic_moves);

                // Si le coup est en train de charger on increment le compteur de frames
                if (loading_move)
                {
                    loading_frames[i]++;

                    //  On verifie si la charge vient d'etre activee
                    if (loading_frames[i] == loading_frames_needed)
                        available_charges[i] = true;
                }

                // Si le joueur n'est plus en train de charger, le compteur est remis à zero et la charge n'est plus active
                if (!loading_move && available_charges[i])
                {
                    loading_frames[i] = 0;
                    available_charges[i] = false;
                }
            }

            #endregion

            #region CHARGE : ARRIERE, BASSE, AVANT, HAUTE

            int[,] moves_lists_id = new int[4,3];
            // BACK
            moves_lists_id[0, 0] = (int)BMove.BACK;
            moves_lists_id[0, 1] = (int)BMove.DOWN_BACK;
            moves_lists_id[0, 2] = (int)BMove.UP_BACK;
            // DOWN
            moves_lists_id[1, 0] = (int)BMove.DOWN;
            moves_lists_id[1, 1] = (int)BMove.DOWN_BACK;
            moves_lists_id[1, 2] = (int)BMove.DOWN_FORWARD;
            // FORWARD
            moves_lists_id[2, 0] = (int)BMove.FORWARD;
            moves_lists_id[2, 1] = (int)BMove.DOWN_FORWARD;
            moves_lists_id[2, 2] = (int)BMove.UP_FORWARD;
            // UP
            moves_lists_id[3, 0] = (int)BMove.UP;
            moves_lists_id[3, 1] = (int)BMove.UP_BACK;
            moves_lists_id[3, 2] = (int)BMove.UP_FORWARD;

            // grace au tableau moves_lists_id on passe chacune de ces directions en revue de la même façon
            for (int i = 0; i < moves_lists_id.Length; i++)
            {
                // on récupère l'index du coup pour les tableaux loading_frames et available_charges 
                // ('i' ne peut pas correspondre à l'index puisqu'on recommence une boucle à zero après avoir passé d'autres coups en revue)
                int move_index = i + moves_id.Length; 

                // Pour savoir si le joueur est en train de charger l'une des directions
                bool loading_move = isOneOfTheseMovesHappening(moves_lists_id[i, 0], moves_lists_id[i, 1], moves_lists_id[i, 2], _last_basic_moves);
                
                // Si la direction est en train de charger on increment le compteur de frames
                if (loading_move)
                {
                    loading_frames[move_index]++;

                    //  On verifie si la charge vient d'etre activee
                    if (loading_frames[move_index] == loading_frames_needed)
                        available_charges[move_index] = true;
                }

                // Si le joueur n'est plus en train de charger, le compteur est remis à zero et la charge n'est plus active
                if (!loading_move && available_charges[move_index])
                {
                    loading_frames[move_index] = 0;
                    available_charges[move_index] = false;
                }
            }

            #endregion
        }

        private bool isMoveHappening(int _move_id, List<int> _current_moves)
        {
            bool happening = false;
            int i = 0;
            while (i < _current_moves.Count && !happening)
            {
                happening = (_current_moves[i] == _move_id);
                i++;
            }
            return happening;
        }

        private bool isOneOfTheseMovesHappening(int _move_id_one, int _move_id_two, int _move_id_three, List<int> _current_moves)
        {
            bool happening = false;
            int i = 0;
            while (i < _current_moves.Count && !happening)
            {
                happening = (_current_moves[i] == _move_id_one || _current_moves[i] == _move_id_two || _current_moves[i] == _move_id_three);
                i++;
            }
            return happening;
        }

        #endregion
    }
}
